package com.qyer.search.engine;

import static com.qyer.commons.utils.InvocationUtils.getFutureContent;

import com.qyer.commons.exception.InvocationException;
import com.qyer.search.enums.FieldsMode;
import com.qyer.search.exception.SearchException;
import com.qyer.search.model.SearchParameter;
import com.qyer.search.model.SearchParameterEntity;
import com.qyer.search.model.SearchParameterOrigin;
import com.qyer.search.searchplan.SQPlan2;
import com.qyer.search.searchplan.SQPlan;
import com.qyer.search.searchplan.SQPlan3;
import com.qyer.search.threading.SearchingThreadPoolHolder;
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * User: Z J Wu Date: 2015/12/17 Time: 13:58 Package: com.qyer.search
 */
public class ForkJoinESEngine extends AbstractESEngine {

  private static class InnerHolder {

    private static final ForkJoinESEngine INSTANCE = new ForkJoinESEngine();
  }

  private ForkJoinESEngine() {
    buildClient();
  }

  public static AbstractESEngine getInstance() {
    //System.out.println("ESEngine getInstance~");
    return InnerHolder.INSTANCE;
  }

  @Override public List<String> forkSearch(SearchParameter searchParameter, List<SQPlan> plans,
                                           boolean showHighlight, boolean simpleResult) throws
    SearchException {
    RecursiveSearchTask rst = new RecursiveSearchTask(this, plans, showHighlight, simpleResult);
    ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
    Future<List<String>> future = service.submit(rst);
    List<String> resultList;
    try {
      resultList = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
    } catch (InvocationException e) {
      throw new SearchException(e);
    }
    if (rst.isCompletedAbnormally()) {
      throw new SearchException(rst.getException());
    }
    return resultList;
  }

  @Override public List<String> forkSearch(SearchParameterOrigin searchParameter, List<SQPlan> plans,
                                           boolean showHighlight, boolean simpleResult) throws
    SearchException {
    RecursiveSearchTask rst = new RecursiveSearchTask(this, plans, showHighlight, simpleResult);
    ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
    Future<List<String>> future = service.submit(rst);
    List<String> resultList;
    try {
      resultList = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
    } catch (InvocationException e) {
      throw new SearchException(e);
    }
    if (rst.isCompletedAbnormally()) {
      throw new SearchException(rst.getException());
    }
    return resultList;
  }

  //老版
  public List<String> forkSearch(SearchParameterOrigin searchParameter, List<SQPlan> plans,
                                           boolean showHighlight, boolean simpleResult, boolean basic) throws
    SearchException {
    RecursiveBasicSearchTask rst = new RecursiveBasicSearchTask(this, plans, showHighlight, simpleResult, basic);
    ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
    Future<List<String>> future = service.submit(rst);
    List<String> resultList;
    try {
      resultList = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
    } catch (InvocationException e) {
      throw new SearchException(e);
    }
    if (rst.isCompletedAbnormally()) {
      throw new SearchException(rst.getException());
    }
    return resultList;
  }

  public List<String> forkSearchThread(SearchParameterOrigin searchParameter, List<SQPlan> plans,
                                 boolean showHighlight, boolean simpleResult, boolean basic) throws
    SearchException {
    List<String> resultList;
    int size_plan = 0;
    if(CollectionUtils.isNotEmpty(plans)){
      size_plan = plans.size();
    }
    RecursiveBasicSearchTask rst = new RecursiveBasicSearchTask(this, plans, showHighlight, simpleResult, basic);
    if(size_plan > 1) {
      ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
      Future<List<String>> future = service.submit(rst);

      try {
        resultList = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
      } catch (InvocationException e) {
        throw new SearchException(e);
      }
      if (rst.isCompletedAbnormally()) {
        throw new SearchException(rst.getException());
      }
    }else if(size_plan == 1){
      resultList = rst.atomicPlanSearch(plans.get(0));
      if(resultList == null)
        resultList = new ArrayList<>();
    }else {
      resultList = new ArrayList<>();
    }
    return resultList;
  }

  //ztag
  public Set<String> forkSearch(SearchParameterEntity searchParameter, List<SQPlan2> plans,
                                 boolean showHighlight, FieldsMode mode) throws
    SearchException {
    //System.out.println("forkSearch go");
    RecursiveSearchASSetTask rst = new RecursiveSearchASSetTask(this, plans, showHighlight, mode);
    ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
    Future<Set<String>> future = service.submit(rst);
    Set<String> resultSet;
    try {
      resultSet = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
    } catch (InvocationException e) {
      throw new SearchException(e);
    }
    if (rst.isCompletedAbnormally()) {
      throw new SearchException(rst.getException());
    }
    return resultSet;
  }

  public Set<String> forkSearchThread(SearchParameterEntity searchParameter, List<SQPlan2> plans,
                                boolean showHighlight, FieldsMode mode) throws
    SearchException {
    //System.out.println("forkSearch go");
    long t1 = System.currentTimeMillis();
    Set<String> resultSet;
    int size_plan = 0;
    if(CollectionUtils.isNotEmpty(plans)){
      size_plan = plans.size();
    }
    RecursiveSearchASSetTask rst = new RecursiveSearchASSetTask(this, plans, showHighlight, mode);
    if(size_plan > 1) {
      ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
      Future<Set<String>> future = service.submit(rst);
      try {
        resultSet = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
      } catch (InvocationException e) {
        throw new SearchException(e);
      }
      if (rst.isCompletedAbnormally()) {
        throw new SearchException(rst.getException());
      }

    }else if(size_plan == 1){
      resultSet = rst.atomicPlanSearch(plans.get(0));
      if(resultSet == null)
        resultSet = new HashSet<>();
    }else {
      resultSet = new HashSet<>();
    }
    //System.out.println("SearchTime:"+(System.currentTimeMillis() - t1));
    return resultSet;
  }


  public Set<String> forkSearchSimple(SearchParameterEntity searchParameter, List<SQPlan3> plans,
                                      boolean showHighlight, FieldsMode mode) throws
    SearchException {
    //System.out.println("forkSearch go");
    long t1 = System.currentTimeMillis();
    Set<String> resultSet;
    int size_plan = 0;
    if(CollectionUtils.isNotEmpty(plans)){
      size_plan = plans.size();
    }
    RecursiveSearchASIDSetTask rst = new RecursiveSearchASIDSetTask(this, plans, showHighlight, mode);
    if(size_plan > 1) {
      ForkJoinPool service = SearchingThreadPoolHolder.getInstance().getForkService();
      Future<Set<String>> future = service.submit(rst);
      try {
        resultSet = getFutureContent(future, TimeUnit.MILLISECONDS, 3000);
      } catch (InvocationException e) {
        throw new SearchException(e);
      }
      if (rst.isCompletedAbnormally()) {
        throw new SearchException(rst.getException());
      }

    }else if(size_plan == 1){
      resultSet = rst.atomicPlanSearch(plans.get(0));
      if(resultSet == null)
        resultSet = new HashSet<>();
    }else {
      resultSet = new HashSet<>();
    }
    //System.out.println("SearchTime:"+(System.currentTimeMillis() - t1));
    return resultSet;
  }



}
